﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Xml;
using Epi.ImportExport;
using Epi.ImportExport.ProjectPackagers;
using CDC.SampleShell.Domain;

namespace CDC.SampleShell.Applications
{
    public sealed class ExportViewModel : ViewModelBase
    {
        private readonly Project _project;
        private readonly Epi.View _defaultForm;
        private string _exportMessages = String.Empty;
        private double _progress = 0.0;
        private string _filePath = String.Empty;
        private bool _isExporting = false;

        public event EventHandler ExportStarted;
        public event EventHandler ExportStopped;

        public string FilePath
        {
            get
            {
                return _filePath;
            }
            set
            {
                _filePath = value;
                RaisePropertyChanged("FilePath");
            }
        }

        public string ExportMessages
        {
            get
            {
                return _exportMessages;
            }
            private set
            {
                _exportMessages = value;
                RaisePropertyChanged("ExportMessages");
            }
        }

        public double Progress
        {
            get
            {
                return _progress;
            }
            private set
            {
                _progress = value;
                RaisePropertyChanged("Progress");
            }
        }

        public ExportViewModel(Project project, Epi.View defaultForm)
        {
            // pre
            Contract.Requires(project != null);
            Contract.Requires(defaultForm != null);

            // post
            Contract.Ensures(_project != null);
            Contract.Ensures(_defaultForm != null);

            _project = project;
            _defaultForm = defaultForm;
        }

        private bool CanExecuteExportCommand()
        {
            if (_isExporting || String.IsNullOrEmpty(FilePath)) return false;
            return true;
        }

        public ICommand ExportCommand { get { return new RelayCommand(Export, CanExecuteExportCommand); } }
        private void Export()
        {
            var sw = new System.Diagnostics.Stopwatch();
            sw.Start();

            ExportMessages = String.Empty;

            if (ExportStarted != null)
            {
                ExportStarted(this, new EventArgs());
            }

            _isExporting = true;

            ExportInfo exportInfo = null;

            Task.Factory.StartNew(() =>
                {
                    try
                    {
                        XmlDataPackager packager = new XmlDataPackager(_defaultForm, "SampleShell Package");
                        packager.UpdateProgress += packager_UpdateProgress;
                        packager.StatusChanged += packager_MessageGenerated;
                        XmlDocument doc = packager.PackageForm();

                        packager.UpdateProgress -= packager_UpdateProgress;
                        packager.StatusChanged -= packager_MessageGenerated;
                        exportInfo = packager.ExportInfo;

                        string compressedText = ImportExportHelper.Zip(doc.OuterXml);
                        compressedText = "[[EPIINFO7_DATAPACKAGE]]" + compressedText;

                        Epi.Configuration.EncryptStringToFile(compressedText, FilePath, "DefaultPasswordPleaseChangeMe", "", "", 1000);
                    }
                    catch (Exception ex)
                    {
                        // TODO: Add exception handling
                        AddMessage(String.Format("Critical error: {0}", ex.Message));
                    }
                    finally
                    {
                        if (ExportStopped != null)
                        {
                            ExportStopped(this, new EventArgs());
                        }
                        _isExporting = false;
                        Progress = 0.0;
                        FilePath = String.Empty;
                    }

                }, CancellationToken.None, TaskCreationOptions.LongRunning, System.Threading.Tasks.TaskScheduler.Default).ContinueWith(delegate
                {
                    sw.Stop();
                    if (sw.Elapsed.TotalSeconds < 60)
                    {
                        AddMessage(String.Format("Export completed in {0} seconds.", sw.Elapsed.TotalSeconds.ToString("F0")));
                    }
                    else
                    {
                        AddMessage(String.Format("Export completed in {0} minutes {1} seconds.", sw.Elapsed.TotalMinutes.ToString("F0"), sw.Elapsed.Seconds.ToString("F0")));
                    }

                    AddMessage(String.Format("{0} records written.", exportInfo.RecordsPackaged[_defaultForm]));
                }
                );
        }

        private void AddMessage(string message)
        {
            Contract.Requires(message != null);

            Contract.Ensures(ExportMessages != null);

            ExportMessages += (message + Environment.NewLine);
        }

        private void packager_MessageGenerated(string message)
        {
            AddMessage(message);
        }

        private void packager_UpdateProgress(double progress)
        {
            Contract.Requires(progress >= 0);

            Contract.Ensures(Progress >= 0);

            Progress = progress;
        }
    }
}
